#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <bcm2835.h>
#include <curl/curl.h>

#include "duvoice/duvoice.h"

#define SOUND_PIN RPI_GPIO_P1_12

/*-------- Types --------*/
typedef enum {
    Listening, Recording
} STATUS;

/*-------- Global variables --------*/
char *Recmd[] = {"arecord", "-D", "plughw:1,0", "-r", "16000", "-c", "1",
                        "-t", "wav", "-f", "S16_LE", "test.wav", NULL};

/*-------- Function prototypes --------*/
extern void GetWheather(int index);

/*-------- Main function --------*/
int main(int argc, char const *argv[])
{
    uint32_t rate;
    STATUS voice_stat = Listening;
    uint32_t loud = 0;
    uint32_t quiet = 0;
    pid_t pid;

    curl_global_init(CURL_GLOBAL_ALL);
    char *tmp = NULL;
    duVoice *du = duVoice_Init();
    if (!du) {
        fputs("create du handler\n", stderr);
        exit(1);
    }

    if (!bcm2835_init()) {
        fputs("init error\n", stderr);
        exit(1);
    }

    // set PIN_mode: input and pull up
    bcm2835_gpio_fsel(SOUND_PIN, BCM2835_GPIO_FSEL_INPT);
    bcm2835_gpio_set_pud(SOUND_PIN, BCM2835_GPIO_PUD_UP);
    // Rising Edge Detect Enable
    bcm2835_gpio_ren(SOUND_PIN);

    while(1) {
        // update rate(number of times in 100ms)
        uint8_t i;
        rate = 0;
        for (i = 0; i < 100; i++) {
            if (bcm2835_gpio_eds(SOUND_PIN)) {
                // clear event detect status flag
                bcm2835_gpio_set_eds(SOUND_PIN);
                rate++;
            }
            bcm2835_delay(1);
        }
        // printf("rate: %d\n", rate);

        // Status machine
        switch (voice_stat) {
        case Listening:
            if (rate > 15) {
                if (++loud > 1) {
                    // fork new process
                    if ((pid = fork()) < 0) {
                        perror("fork");
                        exit(1);
                    }

                    // execute command
                    if (pid > 0) {  // parents
                        voice_stat = Recording;
                        quiet = 0;
                        printf("Recording...\n");
                    } else {        // child
                        int fd = open("/dev/null", O_WRONLY);
                        dup2(fd, STDOUT_FILENO);
                        dup2(fd, STDERR_FILENO);
                        close(fd);
                        execvp(Recmd[0], Recmd);
                        perror("exec");
                        exit(1);
                    }
                }
            } else {
                loud = 0;
            }
            break;
        case Recording:
            if (rate < 15) {
                if (++quiet > 8) {
                    kill(pid, SIGINT);
                    wait(NULL);
                    voice_stat = Listening;
                    loud = 0;
                    // recognize
                    printf("Result:\n");
                    duVoice_SetSpeech(du, "test.wav");
                    tmp = duVoice_Recognize(du);
                    if (tmp) {
                        printf("%s\n", tmp);
                        if (strstr(tmp, "天气")) {
                            if (strstr(tmp, "今天"))
                                GetWheather(0);
                            else if (strstr(tmp, "明天"))
                                GetWheather(1);
                            else if (strstr(tmp, "后天"))
                                GetWheather(2);
                        }
                    }
                    duVoice_Cleanup(du);
                    printf("===============\n");
                }
            } else {
                quiet = 0;
            }
            break;
        default:
            break;
        }
    }

    duVoice_Delete(du);
    bcm2835_close();
    curl_global_cleanup();

    return 0;
}
